<template>
  <a-modal
      :confirmLoading="confirmLoading"
      :maskClosable="false"
      :title="title"
      :visible="visible"
      :width="720"
      @cancel="handleCancel"
      @ok="handleSubmit"
  >
    <a-spin :spinning="confirmLoading">
      <a-form :colon="false" :form="form">
        <!-- 渠道费率 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="渠道费率(%)">
          <a-input-number
              v-decorator="[
                'feeRate',
                { rules: [{ required: true, type: 'number', message: '请输入渠道费率(%)', trigger: 'blur' }] }
              ]"
              allow-clear
              placeholder="请输入渠道费率" style="width: 100%;"
          />
        </a-form-item>
        <!-- 微信 APPID -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="微信 APPID">
          <a-input
              v-decorator="[
              'config.appId',
              { rules: [{ required: true, message: '请输入开放平台上创建的应用的 APPID', trigger: 'blur' }] }
            ]"
              allow-clear placeholder="请输入微信 APPID"
          />
          <template #extra>
            <a
                href="https://pay.weixin.qq.com/index.php/extend/merchant_appid/mapay_platform/account_manage"
                target="_blank"
            >
              前往微信商户平台查看 APPID
            </a>
          </template>
        </a-form-item>
        <!-- 商户号 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="商户号">
          <a-input
              v-decorator="[
                'config.mchId',
                { rules: [{ required: true, message: '请输入商户号', trigger: 'blur' }] }
              ]"
              allow-clear
              placeholder="请输入商户号" style="width: 100%;"
          />
          <template #extra>
            <a href="https://pay.weixin.qq.com/index.php/extend/pay_setting" target="_blank">
              前往微信商户平台查看商户号
            </a>
          </template>
        </a-form-item>
        <!-- 渠道状态 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="渠道状态">
          <a-radio-group
              v-decorator="[
              'status',
              { initialValue: Status.ENABLED.key, rules: [{ required: true, message: '渠道状态不能为空', trigger: 'change' }] }
            ]"
          >
            <a-radio v-for="item in Status.data" :key="item.key" :value="item.key">
              {{ item.name }}
            </a-radio>
          </a-radio-group>
        </a-form-item>
        <!-- API 版本 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="API 版本">
          <a-radio-group
              v-decorator="[
                'config.apiVersion',
                { initialValue: 'v2', rules: [{ required: true, message: '请传入API 版本', trigger: 'change' }] }
              ]"
              @change="onModeChange"
          >
            <a-radio value="v2">v2</a-radio>
            <a-radio value="v3">v3</a-radio>
          </a-radio-group>
        </a-form-item>

        <!-- v2 版本表单项 -->
        <template v-if="form.getFieldValue('config.apiVersion') === 'v2'">
          <!-- 商户密钥 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="商户密钥">
            <a-input
                v-decorator="[
                'config.mchKey',
                { rules: [{ required: true, message: '请输入商户密钥', trigger: 'blur' }] }
              ]"
                allow-clear
                placeholder="请输入商户密钥" style="width: 100%;"
            />
          </a-form-item>
          <!-- apiclient_cert.p12 证书内容 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="apiclient_cert.p12 证书">
            <a-textarea
                v-decorator="[
                  'config.keyContent',
                  { rules: [{ required: true, message: '请输入apiclient_cert.p12 证书', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                :rows="4" allow-clear placeholder="请输入apiclient_cert.p12 证书"
            />
          </a-form-item>
          <!-- apiclient_cert.p12 证书文件上传 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label=" ">
            <a-upload
                :before-upload="p12FileBeforeUpload"
                :custom-request="keyContentUpload"
                :file-list="v2FileList"
                accept=".p12"
                action=""
                @change="onV2FileChange"
            >
              <a-button>
                <a-icon type="upload"/>
                点击上传
              </a-button>
            </a-upload>
          </a-form-item>
        </template>

        <!-- v3 版本表单项 -->
        <template v-else-if="form.getFieldValue('config.apiVersion') === 'v3'">
          <!--  API V3 密钥 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label=" API V3 密钥">
            <a-input
                v-decorator="[
                'config.apiV3Key',
                { rules: [{ required: true, message: '请输入 API V3 密钥', trigger: 'blur' }] }
              ]"
                allow-clear
                placeholder="请输入 API V3 密钥" style="width: 100%;"
            />
          </a-form-item>
          <!-- apiclient_key.pem 证书内容 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="apiclient_key.pem 证书">
            <a-textarea
                v-decorator="[
                  'config.privateKeyContent',
                  { rules: [{ required: true, message: 'apiclient_key.pem 证书', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                allow-clear placeholder="请上传apiclient_key.pem 证书" read-only
            />
          </a-form-item>
          <!-- apiclient_key.pem 证书文件上传 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label=" ">
            <a-upload
                :before-upload="pemFileBeforeUpload"
                :custom-request="privateKeyContentUpload"
                :file-list="v3PrivateKeyFileList"
                accept=".pem"
                action=""
                @change="onV3PrivateKeyFileChange"
            >
              <a-button>
                <a-icon type="upload"/>
                点击上传
              </a-button>
            </a-upload>
          </a-form-item>
          <!-- 证书序列号 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="证书序列号">
            <a-input
                v-decorator="[
                'config.certSerialNo',
                { rules: [{ required: true, message: '请输入证书序列号', trigger: 'blur' }] }
              ]"
                allow-clear
                placeholder="请输入证书序列号" style="width: 100%;"
            />
            <template #extra>
              <a
                  href="https://pay.weixin.qq.com/index.php/core/cert/api_cert#/api-cert-manage"
                  target="_blank"
              >
                前往微信商户平台查看证书序列号
              </a>
            </template>
          </a-form-item>
          <!-- public_key.pem 证书内容 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="public_key.pem 证书">
            <a-textarea
                v-decorator="[
                  'config.publicKeyContent',
                  { rules: [{ required: true, message: '请上传public_key.pem 证书', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                allow-clear placeholder="请上传public_key.pem 证书" read-only
            />
          </a-form-item>
          <!-- public_key.pem 证书文件上传 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label=" ">
            <a-upload
                :before-upload="pemFileBeforeUpload"
                :custom-request="publicKeyContentUpload"
                :file-list="v3PublicKeyFileList"
                accept=".pem"
                action=""
                @change="onV3PublicKeyFileChange"
            >
              <a-button>
                <a-icon type="upload"/>
                点击上传
              </a-button>
            </a-upload>
          </a-form-item>
          <!-- 公钥 ID -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="公钥 ID">
            <a-input
                v-decorator="[
                'config.publicKeyId',
                { rules: [{ required: true, message: '请输入公钥 ID', trigger: 'blur' }] }
              ]"
                allow-clear
                placeholder="请输入公钥 ID" style="width: 100%;"
            />
            <template #extra>
              <a
                  href="https://pay.weixin.qq.com/doc/v3/merchant/4012153196"
                  target="_blank"
              >
                微信支付公钥产品简介及使用说明
              </a>
            </template>
          </a-form-item>
        </template>
        <!-- 备注 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="备注">
          <a-input v-decorator="['remark']" placeholder="请输入备注"/>
        </a-form-item>
      </a-form>
    </a-spin>
  </a-modal>
</template>

<script>
import * as Api from '@/api/pay/channel'
import StatusEnum from '@/common/enum/Status'
import _ from 'lodash'

export default {
  data() {
    // 默认config生成器
    const defaultConfig = () => ({
      appId: '',
      mchId: '',
      apiVersion: 'v2', // 默认v2
      mchKey: '',
      keyContent: '',
      privateKeyContent: '',
      certSerialNo: '',
      apiV3Key: '',
      publicKeyContent: '',
      publicKeyId: ''
    })
    return {
      title: '',
      labelCol: {span: 7},
      wrapperCol: {span: 13},
      visible: false,
      confirmLoading: false,
      form: this.$form.createForm(this),
      // 当前表单数据
      record: {
        appId: '',
        code: '',
        status: undefined,
        feeRate: undefined,
        remark: '',
        config: defaultConfig()
      },
      defaultConfig,
      // 分别管理各上传组件的 fileList
      v2FileList: [],
      v3PrivateKeyFileList: [],
      v3PublicKeyFileList: [],
    }
  },
  computed: {
    Status() {
      return StatusEnum
    }
  },
  methods: {
    // 打开弹窗并初始化表单
    show(appId, code) {
      this.visible = true
      this.resetForm(appId, code)
      Api.detail(undefined, {appId, code}).then(data => {
        if (data && data.id) {
          this.record = data
          // config从字符串转对象，合并默认值，兼容老数据
          this.record.config = Object.assign(this.defaultConfig(), JSON.parse(this.record.config || '{}'))
          // 统一兼容历史大写写法
          this.record.config.apiVersion = (this.record.config.apiVersion || 'v2').toLowerCase()
          this.title = '编辑支付渠道'
        } else {
          this.record.config = this.defaultConfig()
          this.title = '创建支付渠道'
        }
        this.setFieldsValue()
      })
    },
    // 设置表单初始值，先设置apiVersion再设分支字段，防止动态项未渲染
    setFieldsValue() {
      this.$nextTick(() => {
        const pickKeys = [
          'feeRate', 'config.appId', 'config.mchId', 'status', 'config.apiVersion',
          'config.mchKey', 'config.keyContent', 'config.apiV3Key',
          'config.privateKeyContent', 'config.certSerialNo',
          'config.publicKeyContent', 'config.publicKeyId', 'remark'
        ]
        // 提取数据
        const values = _.pick(this.record, pickKeys)
        values['config']['apiVersion'] = (values['config']['apiVersion'] || 'v2').toLowerCase()

        // 先设置apiVersion，确保动态表单项已渲染
        this.form.setFieldsValue({
          'config.apiVersion': values['config']['apiVersion']
        })

        // 等分支表单项渲染后再赋值
        this.$nextTick(() => {
          const apiVersion = values['config']['apiVersion']
          const commonFields = {
            'feeRate': values['feeRate'],
            'config.appId': values['config']['appId'],
            'status': values['status'],
            'config.mchId': values['config']['mchId'],
            'remark': values['remark']
          }
          let apiVersionFields = {}
          if (apiVersion === 'v2') {
            apiVersionFields = {
              'config.mchKey': values['config']['mchKey'],
              'config.keyContent': values['config']['keyContent']
            }
            // 设置V2上传文件fileList，若已存在内容则显示已上传
            this.v2FileList = values['config']['keyContent']
                ? [{
                  uid: '-1',
                  name: 'apiclient_cert.p12',
                  status: 'done',
                  url: '',
                }]
                : []
            // 清空V3相关上传
            this.v3PrivateKeyFileList = []
            this.v3PublicKeyFileList = []
          } else if (apiVersion === 'v3') {
            apiVersionFields = {
              'config.apiV3Key': values['config']['apiV3Key'],
              'config.privateKeyContent': values['config']['privateKeyContent'],
              'config.certSerialNo': values['config']['certSerialNo'],
              'config.publicKeyContent': values['config']['publicKeyContent'],
              'config.publicKeyId': values['config']['publicKeyId']
            }
            // V3私钥文件
            this.v3PrivateKeyFileList = values['config']['privateKeyContent']
                ? [{
                  uid: '-2',
                  name: 'apiclient_key.pem',
                  status: 'done',
                  url: '',
                }]
                : []
            // V3公钥文件
            this.v3PublicKeyFileList = values['config']['publicKeyContent']
                ? [{
                  uid: '-3',
                  name: 'public_key.pem',
                  status: 'done',
                  url: '',
                }]
                : []
            // 清空V2相关上传
            this.v2FileList = []
          }
          this.form.setFieldsValue({
            ...commonFields,
            ...apiVersionFields
          })
        })
      })
    },
    // 重置表单数据和上传fileList
    resetForm(appId, code) {
      this.record = {
        appId,
        code,
        status: this.Status.ENABLED.key,
        remark: '',
        feeRate: null,
        config: this.defaultConfig()
      }
      // 清空所有上传列表
      this.v2FileList = []
      this.v3PrivateKeyFileList = []
      this.v3PublicKeyFileList = []
      this.$nextTick(() => {
        this.form.resetFields()
      })
    },
    // 表单提交
    handleSubmit(e) {
      e.preventDefault()
      this.form.validateFields((errors, values) => {
        if (!errors) {
          this.onFormSubmit(values)
        }
      })
    },
    // 关闭弹窗并清空上传fileList
    handleCancel() {
      this.visible = false
      this.form.resetFields()
      this.v2FileList = []
      this.v3PrivateKeyFileList = []
      this.v3PublicKeyFileList = []
    },
    // 表单提交到后端
    onFormSubmit(values) {
      this.confirmLoading = true
      const params = {...this.record, ...values}
      params.config = JSON.stringify(params.config || {})
      const api = this.record && this.record.id ? Api.edit(this.record.id, params) : Api.add(params)
      api
          .then(() => {
            this.$message.success('操作成功', 1.5)
            this.handleCancel()
            this.$emit('handleSubmit', params)
          })
          .finally(() => {
            this.confirmLoading = false
          })
    },
    // 通用文件上传前校验，限制格式和大小
    fileBeforeUpload(file, fileAccept) {
      const ext = '.' + file.name.split('.').pop()
      if (ext !== fileAccept) {
        this.$message.error(`请上传指定格式"${fileAccept}"文件`)
        return false
      }
      const isRightSize = file.size / 1024 / 1024 < 2
      if (!isRightSize) {
        this.$message.error('文件大小超过 2MB')
      }
      return isRightSize
    },
    // p12上传前校验
    p12FileBeforeUpload(file) {
      return this.fileBeforeUpload(file, '.p12')
    },
    // pem上传前校验
    pemFileBeforeUpload(file) {
      return this.fileBeforeUpload(file, '.pem')
    },
    // v2上传回调，读取p12内容
    keyContentUpload(event) {
      const readFile = new FileReader()
      readFile.onload = (e) => {
        // base64内容去掉头部
        const content = e.target.result.split(',')[1]
        this.record.config['keyContent'] = content
        this.form.setFieldsValue({
          [`config.keyContent`]: content
        })
        // 上传成功后，设置fileList
        this.v2FileList = [{
          uid: event.file.uid || '-1',
          name: event.file.name,
          status: 'done',
          url: '',
        }]
        event.onSuccess && event.onSuccess()
      }
      readFile.readAsDataURL(event.file)
    },
    // v3私钥pem上传回调
    privateKeyContentUpload(event) {
      const readFile = new FileReader()
      readFile.onload = (e) => {
        this.record.config['privateKeyContent'] = e.target.result
        this.form.setFieldsValue({
          [`config.privateKeyContent`]: e.target.result
        })
        this.v3PrivateKeyFileList = [{
          uid: event.file.uid || '-2',
          name: event.file.name,
          status: 'done',
          url: '',
        }]
        event.onSuccess && event.onSuccess()
      }
      readFile.readAsText(event.file)
    },
    // v3公钥pem上传回调
    publicKeyContentUpload(event) {
      const readFile = new FileReader()
      readFile.onload = (e) => {
        this.record.config['publicKeyContent'] = e.target.result
        this.form.setFieldsValue({
          [`config.publicKeyContent`]: e.target.result
        })
        this.v3PublicKeyFileList = [{
          uid: event.file.uid || '-3',
          name: event.file.name,
          status: 'done',
          url: '',
        }]
        event.onSuccess && event.onSuccess()
      }
      readFile.readAsText(event.file)
    },
    // v2上传变更事件，支持删除
    onV2FileChange({fileList}) {
      this.v2FileList = fileList
      if (fileList.length === 0) {
        this.form.setFieldsValue({'config.keyContent': undefined})
        this.record.config['keyContent'] = ''
      }
    },
    // v3私钥上传变更事件，支持删除
    onV3PrivateKeyFileChange({fileList}) {
      this.v3PrivateKeyFileList = fileList
      if (fileList.length === 0) {
        this.form.setFieldsValue({'config.privateKeyContent': undefined})
        this.record.config['privateKeyContent'] = ''
      }
    },
    // v3公钥上传变更事件，支持删除
    onV3PublicKeyFileChange({fileList}) {
      this.v3PublicKeyFileList = fileList
      if (fileList.length === 0) {
        this.form.setFieldsValue({'config.publicKeyContent': undefined})
        this.record.config['publicKeyContent'] = ''
      }
    },
    // 切换API版本，清空无关分支的内容与上传列表
    onModeChange(e) {
      const mode = e.target.value
      if (mode === 'v2') {
        // 切到v2，清空v3相关
        this.v3PrivateKeyFileList = []
        this.v3PublicKeyFileList = []
        this.form.setFieldsValue({
          'config.apiV3Key': undefined,
          'config.privateKeyContent': undefined,
          'config.certSerialNo': undefined,
          'config.publicKeyContent': undefined,
          'config.publicKeyId': undefined
        })
        this.record.config.apiV3Key = ''
        this.record.config.privateKeyContent = ''
        this.record.config.certSerialNo = ''
        this.record.config.publicKeyContent = ''
        this.record.config.publicKeyId = ''
      } else if (mode === 'v3') {
        // 切到v3，清空v2相关
        this.v2FileList = []
        this.form.setFieldsValue({
          'config.mchKey': undefined,
          'config.keyContent': undefined
        })
        this.record.config.mchKey = ''
        this.record.config.keyContent = ''
      }
    }
  }
}
</script>

<style lang="less" scoped>
/deep/ .ant-form-item {
  margin-bottom: 18px !important;
}
</style>